package com.fdb.efp.nls.service.impl.yed;

import com.alibaba.fastjson.JSONObject;
import com.fdb.basic.framework.core.base.FrameworkService;
import com.fdb.basic.framework.core.util.UUIDUtil;
import com.fdb.efp.console.common.YedConstantSet;
import com.fdb.efp.console.common.YedEnums;
import com.fdb.efp.nls.service.facade.SCfgParamService;
import com.fdb.efp.console.service.vo.SCfgParamVO;
import com.fdb.efp.nls.common.ImageBizConstant;
import com.fdb.efp.nls.common.UploadRtMsg;
import com.fdb.efp.nls.common.bo.UpLoadFileVO;
import com.fdb.efp.nls.service.vo.YedUploadRecordVO;
import com.fdb.efp.nls.service.dao.ImageBizDetailDao;
import com.fdb.efp.nls.service.dao.ImageBizInfoDao;
import com.fdb.efp.nls.service.dao.YedUploadRecordDao;
import com.fdb.efp.nls.service.domain.ImageBizDetail;
import com.fdb.efp.nls.service.domain.ImageBizInfo;
import com.fdb.efp.nls.service.domain.YedUploadRecord;
import com.fdb.efp.nls.service.facade.UpLoadFileService;
import com.fdb.efp.nls.service.facade.yed.YedUploadService;
import com.fdb.efp.nls.service.facade.NlsApplyInfoService;
import com.fdb.efp.nls.service.facade.sx.NlsCreditInfoService;
import com.fdb.efp.nls.service.vo.NlsApplyInfoVO;
import com.fdb.efp.nls.service.vo.sx.NlsCreditInfoVO;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Objects;


/**
 * 优e贷文件上传服务（授信）
 *
 * @author zhangxc
 */
@Service("yedUploadService")
public class YedUploadServiceImpl implements YedUploadService, FrameworkService {

    private static Logger logger = LoggerFactory.getLogger(YedUploadServiceImpl.class);

    @Autowired
    private YedUploadRecordDao yedUploadRecordDAO;

    @Autowired
    @Qualifier("upLoadFileService")
    private UpLoadFileService upLoadFileService;

    @Autowired
    @Qualifier("nlsCreditInfoService")
    private NlsCreditInfoService nlsCreditInfoService;

    @Autowired
    @Qualifier("nlsApplyInfoService")
    private NlsApplyInfoService nlsApplyInfoService;

    @Autowired
    private ImageBizDetailDao imageBizDetailDao;

    @Autowired
    private ImageBizInfoDao imageBizInfoDao;

    @Autowired
    @Qualifier("sCfgParamService")
    private SCfgParamService sCfgParamService;

    /**
     * 最大处理数配置参数的key
     */
    public final static String MAX_NUM_KEY = "PSD_FILE_HANDLE_NUM";
    /**
     * 重试次数配置参数的key
     */
    public final static String RETRY_NUM_KEY = "PSD_UP_RETRY_NUM";

    /**
     * 切割符号
     */
    private String splitStr = "_";


    @Override
    public Boolean upLoad() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("优e贷文件上传定时任务");
        logger.info("优e贷文件上传定时器开始执行");
        //获取配置信息
        final int[] handleNumArr = getHandleNumArr();
        //取未成功上传的并且上传次数小于等于3的记录进行处理
        logger.info("优e贷文件上传定时器:最大处理数量=" + handleNumArr[0] + "-------重试次数=" + handleNumArr[1]);
        List<YedUploadRecord> yedUploadRecords = yedUploadRecordDAO.selectYedNeedUploadList(handleNumArr[0], handleNumArr[1], YedEnums.PrdIdEnum.YED.getValue());
        if (yedUploadRecords == null || yedUploadRecords.isEmpty()) {
            logger.info("获取到需要上传的文件为空");
            return Boolean.TRUE;
        }
        logger.info("开始循环处理优e贷文件上传,总共需要处理的记录数量为：", yedUploadRecords.size());
        for (YedUploadRecord yedUploadRecord : yedUploadRecords) {
            //一条条信息上传
            yedUploadRecord.setUpNum(yedUploadRecord.getUpNum() + 1);
            yedUploadRecord.setUpTime(new Date());
            try {
                //判断文件是否存在 不存在则保存日志并且跳过
                if (!new File(yedUploadRecord.getFileUrl()).exists()) {
                    throw new RuntimeException("根据文件路径获取到的文件不存在,文件路径为：" + yedUploadRecord.getFileUrl());
                }

                final YedImgInfo imgInfo = getImgInfo(yedUploadRecord.getFileType());
                //根据文件名获取相应的授信或者用信数据
                YedNlsStamInfo yedNlsStamInfo = getNlsStamInfo(yedUploadRecord.getApplSeq(), imgInfo);
                if (Objects.isNull(yedNlsStamInfo)) {
                    throw new RuntimeException("根据流水号：" +yedUploadRecord.getApplSeq() + "获取到的授信记录为空.文件类型为:" + yedUploadRecord.getFileType());
                }
                //根据授信记录获取成功的上传记录，如果获取得到 则后面的上传操作使用获取到的批次号进行文件追加
                UpLoadFileVO upLoadFileVO = upLoadFileService.queryFirstUpLoadFileByReq(yedUploadRecord.getApplSeq(), "SUCCESS");
                String startDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                if (Objects.isNull(upLoadFileVO)) {
                    //做文件上传
                    String retMsg = YedUploadFileUtils.uploadOneFile(yedNlsStamInfo, imgInfo,
                            yedUploadRecord.getFileUrl(),
                            startDate,
                            startDate
                    );
                    //解析返回的报文
                    UploadRtMsg uploadRtMsg = YedUploadFileUtils.explainRetMsg(retMsg);
                    if (uploadRtMsg.isSuccess()) {
                        UpLoadFileVO saveUploadFileVO = getUpLoadFileVO(yedUploadRecord, yedNlsStamInfo, startDate, uploadRtMsg, imgInfo);
                        saveUploadFileVO.setState("SUCCESS");
                        upLoadFileService.insertUpLoadFile(saveUploadFileVO);
                        //删除文件
                        deleteFile(yedUploadRecord);
                    }
                    yedUploadRecord.setUpSta(uploadRtMsg.isSuccess() ? 1 : 2);
                    yedUploadRecord.setUpRetMsg(JSONObject.toJSONString(uploadRtMsg));
                    yedUploadRecordDAO.updateYedUploadRecordById(yedUploadRecord);
                } else {
                    //做文件追加
                    String retMsg = YedUploadFileUtils.addOneFile(yedNlsStamInfo, imgInfo,
                            startDate, yedUploadRecord.getFileUrl(),
                            upLoadFileVO.getStartDate(),
                            upLoadFileVO.getBatch()
                    );
                    //解析返回的报文
                    UploadRtMsg uploadRtMsg = YedUploadFileUtils.explainRetMsg(retMsg);
                    if (uploadRtMsg.isSuccess()) {
                        UpLoadFileVO saveUploadFileVO = getUpLoadFileVO(yedUploadRecord, yedNlsStamInfo, startDate, uploadRtMsg, imgInfo);
                        saveUploadFileVO.setAddFileState("SUCCESS");
                        saveUploadFileVO.setState("SUCCESS");
                        saveUploadFileVO.setBatch(upLoadFileVO.getBatch());
                        upLoadFileService.insertUpLoadFile(saveUploadFileVO);
                        deleteFile(yedUploadRecord);
                    }
                    yedUploadRecord.setUpSta(uploadRtMsg.isSuccess() ? 1 : 2);
                    yedUploadRecord.setUpRetMsg(JSONObject.toJSONString(uploadRtMsg));
                    yedUploadRecordDAO.updateYedUploadRecordById(yedUploadRecord);
                }
            } catch (Exception e) {
                logger.error("上传优e贷文件影像平台发生异常，申请信息为：" + JSONObject.toJSONString(yedUploadRecord), e);
                yedUploadRecord.setUpSta(2);
                yedUploadRecord.setUpErrMsg(e.getLocalizedMessage());
                yedUploadRecordDAO.updateYedUploadRecordById(yedUploadRecord);
                continue;
            }
        }
        stopWatch.stop();
        logger.info("优e贷上传本次定时任务耗时为：", stopWatch.shortSummary());
        return Boolean.TRUE;
    }

    private void deleteFile(YedUploadRecord yedUploadRecord) {
        File file = new File(yedUploadRecord.getFileUrl());
        if (file.exists()) {
            logger.info("优e贷-开始删除文件：" + file.getAbsolutePath());
            file.delete();
            logger.info("优e贷-删除文件：" + file.getAbsolutePath() + "成功");
        }
        //判断上级目录是否已经为空 如果为空 那么删除
        File dir = new File(FilenameUtils.getFullPath(yedUploadRecord.getFileUrl()));
        if (dir.listFiles().length < 1) {
            dir.delete();
        }
    }

    @Override
    public Integer insert(YedUploadRecordVO yedUploadRecordVO) {
        //判断该文件路径在数据库是否已经存在了
        if (yedUploadRecordDAO.countByFileUrl(yedUploadRecordVO.getFileUrl()) > 0) {
            return -1;
        }
        return yedUploadRecordDAO.insertYedUploadRecord(beanCopy(yedUploadRecordVO,new YedUploadRecord()));
    }

    @Override
    public Integer insertByFileUrl(String contFileUrl) {
        logger.info("要保存需要上传到影像平台的文件的路径为：", contFileUrl);
        //判断该文件路径在数据库是否已经存在了
        if (yedUploadRecordDAO.countByFileUrl(contFileUrl) > 0) {
            return -1;
        }
        YedUploadRecord record = new YedUploadRecord();
        record.setRecordId(UUIDUtil.getUUID());
        record.setCreateTime(new Date());
        record.setUpSta(0);
        record.setUpNum(0);
        record.setFileUrl(contFileUrl);
        record.setPrdId(YedConstantSet.prdId);

        return yedUploadRecordDAO.insertYedUploadRecord(record);
    }

    @Override
    public YedUploadRecordVO queryByCond(YedUploadRecordVO yedUploadRecordVO) {
        logger.debug("当前查询参数信息为:"+ yedUploadRecordVO);
        try {
            YedUploadRecord uploadRecord = new YedUploadRecord();
            beanCopy(yedUploadRecordVO, uploadRecord);
            YedUploadRecord queryUploadRecord = yedUploadRecordDAO.selectYedUploadRecordObjSingle(uploadRecord);
            if (Objects.nonNull(queryUploadRecord)) {
                YedUploadRecordVO outUploadRecord = beanCopy(queryUploadRecord,new YedUploadRecordVO());
                logger.debug("当前查询结果为:"+ outUploadRecord.toString());
                return outUploadRecord;
            } else {
                logger.debug("当前查询结果为空!");
            }
        } catch (Exception e) {
            logger.error("查询数据发生异常!", e);
        }
        return null;
    }

    /**
     * 获取申请流水信息
     *
     * @param applySeq   流水号
     * @param yedImgInfo 影像信息
     * @return
     */
    private YedNlsStamInfo getNlsStamInfo(String applySeq, YedImgInfo yedImgInfo) {
        //获取文件类型 根据类型确定查询的是用信 还是授信记录
        YedNlsStamInfo result = null;
        if (yedImgInfo.getApplyStage()==2) {
            //合同文件查询用信记录
            NlsApplyInfoVO param = new NlsApplyInfoVO();
            param.setApplySeq(applySeq);
            NlsApplyInfoVO nlsApplyInfoVO = nlsApplyInfoService.queryByPk(param);
            if (Objects.isNull(nlsApplyInfoVO)) {
                return result;
            }
            result = new YedNlsStamInfo();
            result.setApplySeq(applySeq);
            result.setCusCertCode(nlsApplyInfoVO.getCertCode());
            result.setChannel(nlsApplyInfoVO.getChannelNo());
            result.setCusCertType(nlsApplyInfoVO.getCertType());
            result.setCusName(nlsApplyInfoVO.getCusName());
            result.setPrdId(nlsApplyInfoVO.getPrdId());
            result.setPrdName(nlsApplyInfoVO.getPrdName());
            result.setTime(nlsApplyInfoVO.getApplyTime());
        } else if (yedImgInfo.getApplyStage()==1) {
            NlsCreditInfoVO nlsCreditInfoVO = nlsCreditInfoService.queryByLmtApplySeq(applySeq);
            if (Objects.isNull(nlsCreditInfoVO)) {
                return result;
            }
            result = new YedNlsStamInfo();
            result.setApplySeq(applySeq);
            result.setCusCertCode(nlsCreditInfoVO.getCertCode());
            result.setChannel(nlsCreditInfoVO.getChannelNo());
            result.setCusCertType(nlsCreditInfoVO.getCertType());
            result.setCusName(nlsCreditInfoVO.getCusName());
            result.setPrdId(nlsCreditInfoVO.getPrdId());
            result.setPrdName(nlsCreditInfoVO.getPrdName());
            result.setTime(nlsCreditInfoVO.getCreateTime());
        }
        return result;
    }

    private final YedImgInfo getImgInfo(String aliasName) {

        if (aliasName.equalsIgnoreCase(ImageBizConstant.IMAGE_TYPE_Y01)) {
            //优e贷授权书
            return new YedImgInfo(ImageBizConstant.IMAGE_TYPE_Y01, "Y01", "优e贷授权书", "0003621", 1);
        }
        if (aliasName.equalsIgnoreCase(ImageBizConstant.IMAGE_TYPE_Y02)) {
            //优e贷借款合同
            return new YedImgInfo(ImageBizConstant.IMAGE_TYPE_Y02, "Y02", "优e贷借款合同", "0003623", 2);
        }
        if (aliasName.equalsIgnoreCase(ImageBizConstant.IMAGE_TYPE_Y03)) {
            //优e贷征信报告
            return new YedImgInfo(ImageBizConstant.IMAGE_TYPE_Y03, "Y03", "优e贷征信报告", "0003641", 1);
        }
        if (aliasName.equalsIgnoreCase(ImageBizConstant.IMAGE_TYPE_Y04)) {
            //结清证明
            return new YedImgInfo(ImageBizConstant.IMAGE_TYPE_Y04, "Y04", "优e贷结清证明", "0003631", 2);
        }
        if (aliasName.equalsIgnoreCase(ImageBizConstant.IMAGE_TYPE_Y05)) {
            //结清证明
            return new YedImgInfo(ImageBizConstant.IMAGE_TYPE_Y05, "Y05", "优e贷授信合同", "0003622", 1);
        }


        throw new RuntimeException("根据文件名获取文件类型失败，当前文件名中的类型为：" + aliasName);
    }

    /**
     * 将同步过来的身份证正反面数据插入到影像业务详情表
     *
     * @param targetFile 目标文件
     */
    private void insertImageBizDetail(File targetFile) {
        String[] baseNameArr = getBaseNameArr(targetFile);
        final String imgType = getImgInfo(baseNameArr[1]).getImgType();
        ImageBizDetail imageBizDetail = new ImageBizDetail();
        imageBizDetail.setApplySeq(baseNameArr[0]);
        imageBizDetail.setBizStage("身份证文件同步");
        imageBizDetail.setFileDesc("身份证文件同步");
        imageBizDetail.setFileName(targetFile.getName());
        imageBizDetail.setFilePath(targetFile.getAbsolutePath());
        imageBizDetail.setImageId(imgType);
        imageBizDetail.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        imageBizDetail.setImageType(imgType);
        imageBizDetailDao.insertImageBizDetail(imageBizDetail);
    }

    /**
     * 插入数据到影像业务信息
     *
     * @param targetFile 目标文件
     */
    private void insertImageBizInfo(File targetFile) {
        //插入一条日志数据到影像信息表
        String[] baseNameArr = getBaseNameArr(targetFile);
        NlsCreditInfoVO nlsCreditInfoVO = nlsCreditInfoService.queryByLmtApplySeq(baseNameArr[0]);
        if (Objects.isNull(nlsCreditInfoVO)) {
            return;
        }
        ImageBizInfo param = new ImageBizInfo();
        param.setApplySeq(nlsCreditInfoVO.getLmtApplySeq());
        if (!Objects.isNull(imageBizInfoDao.queryByPk(param))) {
            return;
        }
        ImageBizInfo imageBizInfo = new ImageBizInfo();
        imageBizInfo.setApplySeq(baseNameArr[0]);
        imageBizInfo.setCreateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        imageBizInfo.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        imageBizInfo.setCusId(nlsCreditInfoVO.getCusId());
        imageBizInfo.setCusName(nlsCreditInfoVO.getCusName());
        imageBizInfo.setPrdId(nlsCreditInfoVO.getPrdId());
        imageBizInfo.setPrdCode(nlsCreditInfoVO.getPrdCode());
        imageBizInfo.setPrdName(nlsCreditInfoVO.getPrdName());
        //如下信息先赋空值
        imageBizInfo.setSoltImageAccept("");
        imageBizInfo.setSoltImageCfca("");
        imageBizInfo.setSoltImageThird1("");
        imageBizInfo.setSoltImageThird2("");
        imageBizInfoDao.insertOrUpdateImageBizInfo(imageBizInfo);
    }

    /**
     * 根据信息封装UploadFileVO对象
     *
     * @param yedUploadRecord
     * @param yedNlsStamInfo
     * @param startDate
     * @param uploadRtMsg
     * @return
     */
    private UpLoadFileVO getUpLoadFileVO(YedUploadRecord yedUploadRecord, YedNlsStamInfo yedNlsStamInfo, String startDate, UploadRtMsg uploadRtMsg, YedImgInfo yedImgInfo) {
        UpLoadFileVO saveUploadFileVO = new UpLoadFileVO();
        saveUploadFileVO.setApplySeq(yedNlsStamInfo.getApplySeq());
        saveUploadFileVO.setStartDate(startDate);
        saveUploadFileVO.setImageType(yedImgInfo.getImgType());
        saveUploadFileVO.setBatch(uploadRtMsg.getBatch());
        saveUploadFileVO.setPrdName(StringUtils.isEmpty(yedNlsStamInfo.getPrdName()) ? "广银优e贷" : yedNlsStamInfo.getPrdName());
        saveUploadFileVO.setCusName(yedNlsStamInfo.getCusName());
        saveUploadFileVO.setCertCode(yedNlsStamInfo.getCusCertCode());
        saveUploadFileVO.setFilePath(yedUploadRecord.getFileUrl());
        saveUploadFileVO.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return saveUploadFileVO;
    }

    /**
     * 通过目标文件的文件名进行切割获取信息
     *
     * @param targetFile 目标文件
     * @return
     */
    private String[] getBaseNameArr(File targetFile) {
        return FilenameUtils.getBaseName(targetFile.getName()).split(splitStr);
    }

    /**
     * 关闭流操作
     *
     * @param inputStream      输入流
     * @param fileOutputStream 输出流
     * @throws IOException
     */
    private void closeStream(InputStream inputStream, FileOutputStream fileOutputStream) throws IOException {
        if (fileOutputStream != null) {
            fileOutputStream.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
    }


    /**
     * 获取最大处理数、重试次数
     *
     * @return
     */
    private int[] getHandleNumArr() {
        int[] result = new int[2];
        try {
            SCfgParamVO param = new SCfgParamVO();
            param.setParamKey(MAX_NUM_KEY);
            SCfgParamVO maxNumCfg = sCfgParamService.queryByPk(param);
            if (Objects.isNull(maxNumCfg)) {
                //设置默认值
                result[0] = 50;
            } else {
                result[0] = Integer.parseInt(maxNumCfg.getParamValue());
            }
            param.setParamKey(RETRY_NUM_KEY);
            SCfgParamVO retryNumCfg = sCfgParamService.queryByPk(param);
            if (Objects.isNull(retryNumCfg)) {
                //设置默认值
                result[1] = 3;
            } else {
                result[1] = Integer.parseInt(retryNumCfg.getParamValue());
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return result;
    }
}
